package cn.itcast.nems.common.util;

import cn.hutool.core.lang.Assert;
import cn.itcast.ic.common.bean.BizError;
import cn.itcast.ic.common.bean.BizHttpStatus;
import cn.itcast.ic.common.exception.BizException;
import cn.itcast.nems.common.constant.BigDecimalEum;
import cn.itcast.nems.common.enumeration.CustomBizError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.NumberUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.Objects;
import java.util.regex.Pattern;
/**
 * <p>
 * 数值处理工具
 * </p>
 *
 * @author zhouwei
 * @since 2023/12/10 6:07 PM
 **/
public class NumberUtil {
    private final static Logger logger = LoggerFactory.getLogger(NumberUtil.class);
    // 判断整数数字的正则表达式
    private static final Pattern NUMBER_PATTERN = Pattern.compile("^[-\\+]?[\\d]*$");
    private static  final  BigDecimal  INTEGER_MAX_VALUE  = new BigDecimal(Integer.MAX_VALUE) ;

    /**
     * 校验是否为数字
     * @param str 文本
     * @return boolean
     */
    public static Boolean checkNum(String str,Pattern pattern ) {
        if(!StringUtils.hasText(str)) {
            return true ;
        }
        if(Objects.isNull(pattern)) {
            pattern = NUMBER_PATTERN;
        }
        try {
            // 先将str转成BigDecimal，然后在转成String
            new BigDecimal(str);
        } catch (Exception e) {
            // 如果转换数字失败，说明该str并非全部为数字
            return false;
        }
        return pattern.matcher(str).matches();
    }

    /**
     * 根据单位和操作类型进行换算 , 方便后续设计到币种之间兑换
     *
     * @param source    数额
     * @param unit      单位
     * @param operation 操作类型
     * @return 换算后结果
     */
    public static BigDecimal convert(Object source, Integer unit, BigDecimalEum operation ) {
        if(Objects.isNull(source)) {
            return null;
        }
        BigDecimal bigDecimal = null;
        if (source instanceof BigDecimal) {
            bigDecimal = (BigDecimal) source;
        } else if (source instanceof String) {
            Assert.isTrue(checkNum((String) source ,Pattern.compile("^[0-9]+(.[0-9]{1,})?$")), () -> new BizException(CustomBizError.DATA_TYPE_ERROR));
            bigDecimal = BigDecimal.valueOf(Double.parseDouble((String) source));
        } else if (source.getClass().getSuperclass().equals(Number.class)) {
            bigDecimal = BigDecimal.valueOf(NumberUtils.convertNumberToTargetClass((Number) source, Double.class));
        }
        switch (operation) {
            case DIVIDE_DOUBLE -> {
                return bigDecimal != null ? bigDecimal.divide(BigDecimal.valueOf(unit), 2,RoundingMode.HALF_UP) : null;
            }
            case MULTIPLY_INT -> {
                return BigDecimal.valueOf(unit).multiply(Objects.requireNonNull(bigDecimal));
            }
        }
        return  null;
    }

    /**
     * <p>
     * 元换算成分
     * </p>
     *
     * @param source 需要换算的金额（单位：元）
     * @return 金额（单位：分 ）
     * @author zhouwei
     * @since 2023/12/8 11:33 AM
     **/
    public static Integer convertToCent(Object source){
        BigDecimal bigDecimal  =  NumberUtil.convert(source , 100 , BigDecimalEum.MULTIPLY_INT) ;
        logger.info("元换算成分 请求参数：{}",  bigDecimal);
        return  Objects.nonNull(bigDecimal) ? bigDecimal.setScale(0,RoundingMode.HALF_UP).intValue(): 0 ;
    }
    /**
     * <p>
     * 分换算成元
     * </p>
     *
     * @param source 需要换算的金额（单位：分）
     * @author zhouwei
     * @return 金额（单位：元 ）
     * @since 2023/12/8 11:33 AM
     **/
    public static BigDecimal convertToYuan(Object source){
        return NumberUtil.convert(source , 100 , BigDecimalEum.DIVIDE_DOUBLE) ;
    }

    /**
     * 将文本转化位 integer 类型
     * @param str 文本
     * @param maxLength 限制长度
     * @return 数字
     */
    public static Integer format(String str, Integer maxLength) {
        if(!StringUtils.hasText(str)) {
            return null;
        }
        BigDecimal bigDecimal = new BigDecimal(str);
        if (bigDecimal.compareTo(INTEGER_MAX_VALUE) > 0) {
            throw new BizException(new BizError(BizHttpStatus.SC_BAD_REQUEST, "SERVER_REQUEST_ERROR", "数值不能超过2147483647"));
        }
        int value = bigDecimal.intValue();
        if (Double.compare(value, Math.pow(10D, Double.valueOf(maxLength))) >= 0) {
            throw new BizException(new BizError(BizHttpStatus.SC_BAD_REQUEST, "SERVER_REQUEST_ERROR", "超出长度"));
        }
        return value;
    }


    /**
     * 将数字格式化千分位结果 ，可以自定义间隔符号和保留几位小数
     *
     * @param value       数值，可为 String/六种数值类型/BigDecimal
     * @param round 保留的小数位数，为 null 时的默认规则：若 value 为 bigDecimal 则不进行设置，否则保留两位小数
     * @param delimiter   千分位分隔符，为空时将默认为 “,”
     * @return 格式化后的数据，比如 1,234,567.89
     */
    public static String format(Object value, Integer round, String delimiter) {
        if (Objects.isNull(value)) {
            return null;
        }
        try {
            // 默认保留2位小数
            round = Objects.requireNonNullElse(round, 2);
            // 默认 逗号分隔符
            delimiter = Objects.requireNonNullElse(delimiter, ",");
            BigDecimal bigDecimalVal;
            if (value instanceof BigDecimal) {
                bigDecimalVal = ((BigDecimal) value).setScale(round, RoundingMode.HALF_UP);
            } else {
                bigDecimalVal = new BigDecimal(value.toString()).setScale(round, RoundingMode.HALF_UP);
            }
            NumberFormat instance = NumberFormat.getInstance();
            instance.setMinimumFractionDigits(bigDecimalVal.scale());
            String[] parts = instance.format(bigDecimalVal).split(",");
            return String.join(delimiter, parts);
        } catch (Exception e) {
            logger.info("[格式化数字为千分位表示], 参数: {} 异常: {}", value, e.getMessage());
        }
        return null;
    }
    /**
     * <p>
     * 将数字格式化千分位并保留2位小数的结果
     * </p>
     *
     * @param value 需要转化的数值
     * @author zhouwei
     * @since 2023/12/10 6:03 PM
     **/
    public static String formatToThousands(Object value) {
        return  NumberUtil.format(value , 2 ,",") ;
    }
}
